Skip to content

[Website] Fix service worker cache purging to support multi-tab scenarios#3414

Draft
brandonpayton wants to merge 4 commits intotrunkfrom
ff-loading-issues-with-multiple-tabs
Draft

[Website] Fix service worker cache purging to support multi-tab scenarios#3414
brandonpayton wants to merge 4 commits intotrunkfrom
ff-loading-issues-with-multiple-tabs

Conversation

@brandonpayton
Copy link
Copy Markdown
Member

Summary

  • After a service worker update, cacheFirstFetch now falls back to
    previous-version playground-cache-* caches before going to the
    network, so old tabs can still resolve their hashed asset URLs
  • The activate handler now uses purgeExcessOldCaches() instead of
    purgeEverythingFromPreviousRelease(), keeping the most recent old
    cache (bounded to ~3 versions total)
  • Re-enables the multi-tab deployment E2E test that was skipped due to
    this issue

Problem

When a new version of Playground is deployed, the service worker
immediately activates (skipWaiting()) and purges all old cached
assets. Existing browser tabs still hold references to old hashed asset
URLs (e.g., php_8_3-2286e20c.js). These assets are gone from both
cache and server, causing 404s and "Failed to initialize WordPress"
errors.

This particularly affects users with multiple Playground tabs open
during a deploy.

Approach

Two complementary changes:

  1. Fallback cache search: cacheFirstFetch checks all older
    playground-cache-* caches after a miss in the current build's
    cache, before going to the network. This lets old tabs find their
    hashed assets in the previous version's cache.

  2. Retain one old cache: purgeExcessOldCaches() replaces the
    previous purge-everything behavior. It keeps the most recent old
    cache and deletes the rest, so old tabs have somewhere to find their
    assets. The surviving cache gets cleaned up on the next deploy.

Only the cache-first path needs the fallback — networkFirstFetch
(used for remote.html and /) already fetches fresh content.

Test plan

  • npx nx test playground-remote passes
  • npx nx lint playground-remote passes
  • npx nx e2e playground-website — deployment tests, including the
    re-enabled multi-tab test
  • Manual: open Playground in two tabs, simulate a deploy, confirm
    the first tab doesn't crash

self.serviceWorker.state has been available in Firefox since v120
(Nov 2023). Update the misleading comment and make the @ts-ignore
annotation more descriptive. The guard is kept as a safety net.
After a service worker update, old tabs still hold references to
hashed asset URLs from the previous build. These assets are gone
from the current cache and the server, causing 404s and
"Failed to initialize WordPress" errors.

Search all previous playground-cache-* caches before going to the
network so old tabs can still find their assets.

Also add purgeExcessOldCaches() which keeps the most recent old
cache instead of purging everything, bounding storage to ~3 versions.
Switch from purgeEverythingFromPreviousRelease() to
purgeExcessOldCaches() so old tabs can still resolve their
hashed asset URLs from the previous build's cache.
Copy link
Copy Markdown
Member Author

@brandonpayton brandonpayton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what I think about this yet but would like to explore it.

// hashed asset URLs from the previous build. Search older
// caches before going to the network so those tabs don't 404.
const previousVersionResponse = await matchInPreviousVersionCaches(request);
if (previousVersionResponse) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if all packages produce a hashed filename. I have a vague memory of at least one exception to the name-with-hash approach, but it might have been for Node.js deps consumed by Studio builds. We need to make sure.

Comment on lines +181 to +183
// Keep the last entry (typically the most recent old cache)
// and delete the rest.
const toDelete = oldNames.slice(0, -1);
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit weak to depend up on the last being "typically the most recent". We need to look more closely at this.

@brandonpayton brandonpayton force-pushed the ff-loading-issues-with-multiple-tabs branch from f17dca7 to c14345a Compare March 18, 2026 16:32
The test was skipped because it used an outdated UI flow (the
"Add Playground" modal no longer exists). Rewrite the test to
create a new site via URL query parameters instead, which is
the current pattern for specifying WordPress version and language.
@brandonpayton brandonpayton force-pushed the ff-loading-issues-with-multiple-tabs branch from c14345a to 2912b06 Compare March 18, 2026 18:32
@brandonpayton brandonpayton changed the title Fix service worker cache purging to support multi-tab scenarios [Website] Fix service worker cache purging to support multi-tab scenarios Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant